package mk.com.ldm.corepoint.implementation.client.lib.generators;

import java.util.ArrayList;
import java.util.HashMap;

import mk.com.ldm.corepoint.implementation.client.CoreService;
import mk.com.ldm.corepoint.implementation.client.CoreServiceAsync;
import mk.com.ldm.corepoint.implementation.client.lib.validation.Validator;
import mk.com.ldm.corepoint.implementation.shared.FormObject;
import mk.com.ldm.corepoint.implementation.shared.FormRow;
import mk.com.ldm.corepoint.implementation.shared.TemporaryStorage;

import org.gwt.mosaic.ui.client.InfoPanel;
import org.gwt.mosaic.ui.client.MessageBox;
import org.gwt.mosaic.ui.client.WindowPanel;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * TODO: Remove size and maybe filter from full object maps. Size can be determined through values, 
 * while filters are only required for simple objects i.e. Filter only if object is included in simple map.
 * Perhaps add an object type to the mapping process? (main or modal)
 */

public class FormGenerator {

	private final String SAVE_IMAGE = "<img src='/images/save.png'' />";
	private final String CANCEL_IMAGE = "<img src='/images/cancel.png'' />";
	
	private WidgetFactory widgetFactory;
	private HashMap<String, Integer> widgetMap = new HashMap<String, Integer>();
	private ArrayList<Integer> types = new ArrayList<Integer>();
	private FormObject config = new FormObject();
	private ArrayList<BaseWidget> reference = new ArrayList<BaseWidget>();
	private HashMap<String, BaseWidget> widgets = new HashMap<String, BaseWidget>();
	private HashMap<String,HashMap<String,BaseWidget>> groups = new HashMap<String,HashMap<String,BaseWidget>>();
	private HandlerManager eventBus;
	private HandlerManager handlerManager;
	private EditEvent editEvent;
	private Button save = new Button( SAVE_IMAGE + "<div>Save</div>");
	private Button cancel = new Button( CANCEL_IMAGE + "<div>Cancel</div>");
	private String type;
	private WindowPanel panel;
	CoreServiceAsync rpcService = GWT.create(CoreService.class);
	private HashMap<String, String> params = new HashMap<String, String>();
	private BaseWidget first;
	
	
	
	public HandlerRegistration addEditEvent(EditEventHandler handler){
		return handlerManager.addHandler(EditEvent.TYPE, handler);
	}
	
	public HandlerRegistration addAddEvent(AddEventHandler handler){
		return handlerManager.addHandler(AddEvent.TYPE, handler);
	}
	
	public void fireEvent(GwtEvent<?> event){
		handlerManager.fireEvent(event);
	}
	
	public void setParams(HashMap<String, String> params){
		this.params = params;
	}
	
	public BaseWidget getFirst(){return first;}
	
	
	public FormGenerator(HandlerManager eventBus, WindowPanel panel, String type){
		handlerManager = new HandlerManager(this);
		
		widgetMap.put("BT",0); //Button
		widgetMap.put("TB",1); //TextBox
		widgetMap.put("LB",2); //ListBox
		widgetMap.put("CB",3); //CheckBox
		widgetMap.put("RB",4); //RadioButton
		widgetMap.put("TA",5); //TextArea
		widgetMap.put("RT",6); //RichTextArea
		widgetMap.put("DB",7); //DateBox
		widgetMap.put("UD", 8); //Upload
		widgetMap.put("PT", 9); //PagingTable
		widgetMap.put("LL", 10); //Label
		widgetMap.put("LV", 11); //ListView
		
		this.eventBus = eventBus;
		
		if(panel != null){
			this.panel = panel;
		}
		
		this.type = type;
		
	}
	
	


	public Widget generateForm(FormObject config){
		this.config = config;
		widgetFactory = new WidgetFactory(eventBus);
		VerticalPanel formHolder = new VerticalPanel();
		HTML formTitle = new HTML("<h1>"+config.getFormName()+"</h1>");
		formTitle.setStyleName("lt-Form-title");
		formHolder.add(formTitle);
		formHolder.setStyleName("lt-Form");
		FlexTable formLayout = new FlexTable();
		
		formLayout.setStyleName("lt-Form-content");
		
		
		int currentCol = 0;
		int currentRow = 0;
		
		for(final FormRow c:config.getConfRows()){
			
			if(c.getDbn().equals(config.getPrimary()) && !c.getVal().isEmpty()){
				TemporaryStorage.getInstance().setId(c.getVal());
			}
			
			BaseWidget widget = widgetFactory.getWidget(c, eventBus);
			types.add(widget.getType());
			widget.addStyleName("lt-Form-margin");
			
			if(!c.getTag().equals("")){
				groupByTag(c.getTag(),widget);
			}
			formLayout.setWidget(currentRow, currentCol, widget);
			if(currentRow==0&&currentCol==0){
				first = widget;
			}
			currentCol++;
			

			
			if(currentCol == config.getColumn()){
				currentRow++;
				currentCol = 0;
			}
			
			formLayout.getFlexCellFormatter().setVerticalAlignment(currentRow, currentCol, HasVerticalAlignment.ALIGN_MIDDLE);
			widgets.put(c.getDbn(),widget);
			reference.add(widget);
			saveGrouping();
		}
		
		HorizontalPanel controls = new HorizontalPanel();
//		controls.setStyleName("lt-Form-controls");
		controls.add(save);
		if(panel != null){
			controls.add(cancel);
		}
		formLayout.setWidget(currentRow+1, 0, controls);
		formLayout.getFlexCellFormatter().setColSpan(currentRow+1, 0, config.getColumn());
		formLayout.getFlexCellFormatter().setHorizontalAlignment(currentRow+1, 0, HasHorizontalAlignment.ALIGN_CENTER);
		formLayout.getFlexCellFormatter().setHeight(currentRow+1, 0, "50px");
		formLayout.getFlexCellFormatter().setVerticalAlignment(currentRow+1, 0, HasVerticalAlignment.ALIGN_BOTTOM);
		formLayout.getFlexCellFormatter().setStyleName(currentRow+1, 0,  "lt-Form-controls");
		
		formLayout.setCellSpacing(6);
		formHolder.add(formLayout);
		TemporaryStorage.getInstance().setForm(config);
		TemporaryStorage.getInstance().setReference(reference);
		setBaseEvents();
		return formHolder;
		
	}
	
	private void groupByTag(String tag, BaseWidget widget){
		if(!tag.isEmpty()){
			if(groups.isEmpty() || groups.get(tag.split(",")[0]) == null){
				HashMap<String,BaseWidget> item = new HashMap<String,BaseWidget>();
				item.put(tag.split(",")[1], widget);
				groups.put(tag.split(",")[0], item);
			} else if(groups.get(tag.split(",")[0]) != null) {
				groups.get(tag.split(",")[0]).put(tag.split(",")[0], widget);
			}
		}
	}
	

	private void saveGrouping(){
		TemporaryStorage.getInstance().setGroups(groups);
	};
	
	
	private void saveCurrentState(){
		for(FormRow c:TemporaryStorage.getInstance().getForm().getConfRows()){
			if(!c.getDbn().isEmpty()){
				if(c.getInp().equals("LV"))
					c.setVal(widgets.get(c.getDbn()).getTitle());
				else
					c.setVal(widgets.get(c.getDbn()).getValue());
			}
		}
	}
	
	private void setBaseEvents(){
		final String id;
		if(type.equals("insert"))  id = " ";
		else id = TemporaryStorage.getInstance().getId();
		save.addClickHandler(new ClickHandler(){

			@Override
			public void onClick(ClickEvent event) {
				if(!Validator.getInstance().checkForErrors()){
				saveCurrentState();
				
					rpcService.saveObject(TemporaryStorage.getInstance().getForm(), id, type, params, new AsyncCallback<ArrayList<String>>(){

						@Override
						public void onFailure(Throwable caught) {
							InfoPanel.show("Server", "Failed to communicate with the server.");
						}

						@Override
						public void onSuccess(ArrayList<String> result) {
							InfoPanel.show("Server", "Item saved.");
							if(id.equals(" ")){
								if(result.size()>1){
									AddEvent event = new AddEvent(result.get(0), result.get(1));
									fireEvent(event);
								}
							}
							else{
								EditEvent event = new EditEvent();
								fireEvent(event);
							}
							if(panel != null){
								panel.hide();
							}
							else{
								History.newItem(History.getToken().split("/")[0]+"/List");
							}
						}
						
					});
				}
				
			}
			
		});
		
		cancel.addClickHandler(new ClickHandler(){

			
			public void onClick(ClickEvent event) {
				if(panel != null){
					panel.hide();
				}				
			}
			
		});
		
		cancel.addKeyDownHandler(new  KeyDownHandler(){

			@Override
			public void onKeyDown(KeyDownEvent event) {
				if(event.getNativeKeyCode()==27){
					panel.hide();
				}
			}
			
		});
	}




	
	
}
